package com.google.code.shardbatis.util;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.google.code.shardbatis.builder.ShardConfigHolder;
import com.google.code.shardbatis.strategy.ShardStrategy;

public class ConfigHandler extends DefaultHandler {
	
	private String parentElement;
	private String parentTable;
	ShardConfigHolder configHolder;

	public ConfigHandler(ShardConfigHolder configHolder) {
		this.configHolder = configHolder;
	}

	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		if ("strategy".equals(qName)) {
			String table = attributes.getValue("tableName");
			String className = attributes.getValue("strategyClass");
			ShardStrategy strategy;
			try {
				Class<?> clazz = Class.forName(className);
				strategy = (ShardStrategy) clazz.newInstance();
				configHolder.register(table, strategy);
				this.parentElement = qName;
				this.parentTable = table;
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		else if (("property".equals(qName)) && ("strategy".equals(parentElement))) {
			ShardStrategy strategy = configHolder.getStrategy(parentTable);
			if (null != strategy) {
				String name = attributes.getValue("name");
				String value = attributes.getValue("value");
				Field field = null;
				Class<?> clazz = strategy.getClass();
				while (null == field && null != clazz) {
					try { field = clazz.getDeclaredField(name); }
					catch (NoSuchFieldException e) { clazz = clazz.getSuperclass(); }
				}
				if (null == field) {
					throw new RuntimeException("not field.");
				}
				String methodName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
				Method method = null;
				try {
					method = strategy.getClass().getMethod(methodName, field.getType());
				}
				catch (NoSuchMethodException e) {
					throw new RuntimeException("not method.");
				}
				catch (SecurityException e) {
					throw new RuntimeException("not method.");
				}
				Object fieldValue = null;
				switch (field.getType().getName()) {
				case "java.lang.Byte" : fieldValue = Byte.parseByte(value); break;
				case "java.lang.Short" : fieldValue = Short.parseShort(value); break;
				case "java.lang.Integer" : fieldValue = Integer.parseInt(value); break;
				case "java.lang.Long" : fieldValue = Long.parseLong(value); break;
				case "java.lang.Float" : fieldValue = Float.parseFloat(value); break;
				case "java.lang.Double" : fieldValue = Double.parseDouble(value); break;
				case "java.lang.Char" : fieldValue = value.charAt(0); break;
				case "java.lang.Boolean" : fieldValue = Boolean.parseBoolean(value); break;
				case "java.lang.String" : fieldValue = value; break;
				}
				if (null != fieldValue) {
					try { method.invoke(strategy, fieldValue); }
					catch (Throwable e) { e.printStackTrace(); }
				}
			}
		}
		else if (("ignoreList".equals(qName)) || ("parseList".equals(qName))) {
			this.parentElement = qName;
		}

	}

	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		if ("ignoreList".equals(this.parentElement)) {
			configHolder.addIgnoreId(new String(ch, start, length).trim());
		}
		else if ("parseList".equals(this.parentElement)) {
			configHolder.addParseId(new String(ch, start, length).trim());
		}
	}

}
